
#include "Header.h"
#include "EnvelopeManager.h"
#include <math.h>
#include <vector>

class Effect_SideChaining
{
public:
	EnvelopeManager mSideChaining;
	LeapCurveEnvelope up;
	LinearEnvelope distance;
	LeapCurveEnvelope down;
	double mVolyme;
	double mFallback;
	double mFallbackCurve;
	double mFallbackDistance;
	double chainigPosition;
	double mFallbackDistanceCalc;

	Effect_SideChaining()
	{
		mSideChaining.Add(&up);
		mSideChaining.Add(&distance);
		mSideChaining.Add(&down);
	}

	void SetVolyme(double value)
	{
		up.SetY2(1.0);
		up.SetY1(1 - value);
		distance.SetY1(1.0);
		distance.SetY2(1.0);
		down.SetY2(1 - value);
		down.SetY1(1.0);
	}

	void SetFallbackCurve(double value)
	{
		up.SetLeap(value);
		down.SetLeap(value);
	}

	void SetFallback(double value, double beatSamples)
	{
		double fallbackSamples = beatSamples * value;
		double x2 = beatSamples - fallbackSamples;

		up.SetX2(::fmax(0, x2 - mFallbackDistanceCalc));

		distance.SetX1(up.mX2);
		distance.SetX2(x2);

		down.SetX1(x2);
		down.SetX2(beatSamples);
	}

	void SetFallbackDistance(double value, double beatSamples)
	{
		mFallbackDistanceCalc = value * beatSamples;

		SetFallback(mFallback, beatSamples);
	}

	void Process(double chainigPosition, double* sound_left, double* sound_right, double* sound_left_out, double* sound_right_out, int length)
	{
		mSideChaining.CurrentPosition = chainigPosition;
		mSideChaining.ProcessTime(sound_left, sound_left_out, length);
		mSideChaining.ProcessTime(sound_right, sound_right_out, length);
	}

	void Setup(double volume, double fallback, double curve, double distance, int samplesPerBeat)
	{
		SetVolyme(volume);
		SetFallbackCurve(curve);
		SetFallbackDistance(distance, samplesPerBeat);
		SetFallback(fallback, samplesPerBeat);
	}
};

extern "C"
{
	DECLSPEC Effect_SideChaining* STDCALL Effect_SideChaining_Create()
	{
		return new Effect_SideChaining();
	}

	DECLSPEC void STDCALL Effect_SideChaining_Delete(Effect_SideChaining* ptr)
	{
		delete ptr;
	}

	DECLSPEC void STDCALL Effect_SideChaining_Setup(Effect_SideChaining* ptr, double volume, double fallback, double curve, double distance, double samplesPerBeat)
	{
		ptr->Setup(volume, fallback, curve, distance, samplesPerBeat);
	}

	DECLSPEC void STDCALL Effect_SideChaining_Process(Effect_SideChaining* ptr, double samplePos, int length,
		double* wav_in_left, double* wav_in_right, double* wav_out_left, double* wav_out_right)
	{
		ptr->Process(samplePos, wav_in_left, wav_in_right, wav_out_left, wav_out_right, length);
	}
}